/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


/**
 * Test AmbisonicEncoder object.
 */
describe('Encoder', function() {
  // This test is async, override timeout threshold to 5 sec.
  this.timeout(5000);

  const ambisonicOrder = 3;
  const numberOfChannels = Math.pow(ambisonicOrder + 1, 2);
  const sampleRate = 48000;
  const threshold = 7.8e-7;
  const numAngles = 32;
  const numWidths = 32;
  const angles = [
    [-101, 10], [-88, -25], [-69, 25], [-128, -6], [-51, -22], [-107, 47],
    [-122, -46], [-34, 17], [-150, 20], [-46, -56], [-51, 64], [-161, -29],
    [-13, -12], [-165, 54], [-144, -81], [-2, 40], [178, 2], [8, -45],
    [106, 81], [161, -49], [16, 7], [156, 32], [64, -63], [47, 50],
    [147, -15], [39, -20], [114, 44], [108, -41], [55, 17], [122, 8],
    [76, -21], [76, 0],
  ];
  const widths = [
    30, 35, 41, 46, 52, 57, 63, 68, 74, 79, 85, 90, 96, 101, 107, 112, 118,
    123, 129, 134, 140, 145, 151, 156, 162, 167, 173, 178, 184, 189, 195, 200,
  ];
  const angleCoefficients = [
    [
      1, -0.966714084, 0.173648179, -0.187910184, 0.314636409, -0.290756136,
      -0.454769462, -0.0565172695, -0.778752446, 0.633265436, 0.122169897,
      0.502735794, -0.24738194, 0.0977219343, -0.302381098, 0.411247373,
    ],
    [
      1, -0.905755699, -0.42261827, 0.0316296853, -0.0496211201, 0.663009822,
      -0.232090712, -0.0231528133, -0.709615111, 0.585304, 0.0468921177,
      0.0593314208, 0.445221782, -0.0020718989, 0.670588493, -0.0615179278,
    ],
    [
      1, -0.846111238, 0.42261827, 0.32479167, -0.475984663, -0.619350255,
      -0.232090712, 0.237746298, -0.528634489, 0.267186135, -0.449807,
      0.0554244146, -0.445221782, -0.0212754402, -0.49956128, -0.524382293,
    ],
    [
      1, -0.783693969, -0.104528464, -0.612288833, 0.831119478, 0.141886696,
      -0.48361069, 0.110854037, -0.207221359, -0.316297948, -0.194259837,
      0.453694463, 0.153937444, 0.354464978, 0.0484344177, 0.710416794,
    ],
    [
      1, -0.720557213, -0.37460658, 0.583495677, -0.72822696, 0.467524648,
      -0.289504856, -0.378593981, -0.154789418, -0.286077917, 0.609996259,
      0.131646529, 0.430488437, -0.106605254, 0.129658699, -0.561459541,
    ],
    [
      1, -0.652198255, 0.7313537, -0.199397027, 0.225246966, -0.826166809,
      0.302317351, -0.252584547, -0.333942354, 0.157819912, 0.368359119,
      -0.668732166, -0.119067609, -0.204451934, -0.546114862, 0.194891363,
    ],
    [
      1, -0.589103699, -0.719339788, -0.368112862, 0.375606716, 0.733983815,
      0.276174635, 0.458643973, -0.183195636, -0.0277005509, -0.604160666,
      -0.572601378, 0.148454204, -0.35780105, 0.294668853, 0.263553143,
    ],
    [
      1, -0.534758806, 0.29237169, 0.792812586, -0.734326363, -0.270803303,
      -0.37177819, 0.401482373, 0.296687126, -0.676290572, -0.480075419,
      0.18750824, -0.376076847, -0.277992398, 0.193963051, -0.14375,
    ],
    [
      1, -0.469846308, 0.342020154, -0.813797653, 0.662266672, -0.278335214,
      -0.324533343, -0.482090712, 0.382359833, -0.655990362, 0.506488502,
      0.119436152, -0.413008332, 0.206869483, 0.292421281, 2.00839122E-16,
    ],
    [
      1, -0.402249724, -0.829037547, 0.38844803, -0.270638317, 0.577604532,
      0.530954957, -0.557786226, -0.00945089851, -0.0924987495, 0.50170511,
      -0.600178897, -0.180944279, 0.579586, 0.0175199285, -0.102730267,
    ],
    [
      1, -0.340678364, 0.898794055, 0.275875896, -0.162786707, -0.530353427,
      0.711746097, 0.429471731, -0.0346013829, -0.0302351862, -0.327162981,
      -0.634034455, 0.466992587, 0.513430953, -0.0695406348, -0.0593398958,
    ],
    [
      1, -0.284748316, -0.484809607, -0.826969206, 0.40786, 0.239107415,
      -0.14743945, 0.694418311, 0.522037, -0.443597585, -0.442147702,
      -0.0305503, 0.442339838, -0.0887245089, -0.565923214, -0.288075656,
    ],
    [
      1, -0.220035329, -0.207911685, 0.953077734, -0.363229722, 0.0792377219,
      -0.435159087, -0.34321627, 0.744731307, -0.465612888, 0.168867201,
      0.105620585, 0.289398909, -0.457493037, -0.346229076, 0.574984,
    ],
    [
      1, -0.152130023, 0.809017, -0.567756951, 0.149602205, -0.213173479,
      0.481762737, -0.795574307, 0.259118617, -0.113522269, 0.270632952,
      -0.211710572, 0.110245749, -0.790114641, 0.46875, -0.113522269,
    ],
    [
      1, -0.0919498727, -0.987688363, -0.12655814, 0.0201558843, 0.157301068,
      0.96329236, 0.216506347, 0.00654904358, -0.00287835044, -0.0445150398,
      -0.218340546, -0.927262187, -0.300519973, -0.014463813, 0.000935232732,
    ],
    [
      1, -0.0267345663, 0.642787635, 0.765577793, -0.0354505591, -0.0297646821,
      0.119763866, 0.852349, 0.506966591, -0.0371480882, -0.0509536825,
      -0.0174500588, -0.300220519, 0.499704301, 0.72867161, 0.353440464,
    ],
    [
      1, 0.0348782353, 0.0348994955, -0.998782039, -0.0603372976, 0.00210830919,
      -0.498173028, -0.0603740774, 0.8628636, 0.0824860781, -0.00470858067,
      -0.021228401, -0.0522429794, 0.607901871, 0.067335844, -0.784802616,
    ],
    [
      1, 0.0984102413, -0.707106769, 0.700225294, 0.119354479, -0.120527439,
      0.25, -0.857597291, 0.416238517, 0.113686346, -0.188716, 0.0903955773,
      0.176776692, 0.643197954, -0.658130884, 0.255343705,
    ],
    [
      1, 0.150374457, 0.987688363, -0.0431191809, -0.0112306587, 0.257249564,
      0.96329236, -0.0737651214, -0.0179728102, -0.00202510809, -0.0248033386,
      0.357073277, 0.927262187, -0.102389112, -0.0396936387, 0.00224911049,
    ],
    [
      1, 0.213591933, -0.754709601, -0.620315969, -0.229487181, -0.279206365,
      0.354379833, 0.810874164, 0.293730199, 0.18722342, 0.387278438,
      0.241705552, 0.0573833026, -0.701963902, -0.495693773, -0.121584304,
    ],
    [
      1, 0.273582786, 0.121869341, 0.954096615, 0.452107549, 0.0577489212,
      -0.477721781, 0.201394424, 0.723523319, 0.574467659, 0.123202987,
      -0.155093327, -0.178278968, -0.54087472, 0.197166, 0.517253041,
    ],
    [
      1, 0.344932228, 0.529919267, -0.774730504, -0.462855101, 0.316595048,
      -0.0787783638, -0.711084127, 0.4167566, 0.458572268, -0.54845345,
      0.0853509381, -0.42285645, -0.191701353, 0.493829697, -0.148999155,
    ],
    [
      1, 0.408043951, -0.891006529, 0.199016333, 0.140655369, -0.629721403,
      0.690838933, -0.307135642, -0.109892018, -0.0153801022, -0.280234873,
      0.741994202, -0.431898981, 0.361894757, 0.218943492, -0.0723576918,
    ],
    [
      1, 0.470105112, 0.766044438, 0.438380092, 0.35694921, 0.623748541,
      0.380236119, 0.581654966, -0.0249603204, 0.132133916, 0.611428082,
      0.556793451, -0.0252333339, 0.519218266, -0.0427552164, -0.163171798,
    ],
    [
      1, 0.526080906, -0.258819044, -0.810093582, -0.738156319, -0.235835627,
      -0.399519056, 0.363155, 0.328648388, 0.703706, 0.42719838, -0.214255169,
      0.344884604, 0.329924017, -0.19020097, 0.111456089,
    ],
    [
      1, 0.591367722, -0.342020154, 0.730278313, 0.748008728, -0.350324035,
      -0.324533343, -0.432614148, 0.158994168, 0.58449167, -0.572062314,
      -0.150327221, 0.413008332, -0.185638651, -0.121595599, -0.297813386,
    ],
    [
      1, 0.657149613, 0.694658399, -0.292581856, -0.333021492, 0.790671647,
      0.22382538, -0.352029681, -0.299853891, -0.0909336507, -0.51728338,
      0.568519771, -0.203968629, -0.253121316, -0.465764076, 0.279865,
    ],
    [
      1, 0.717771471, -0.656059, -0.233218089, -0.289940596, -0.815623522,
      0.145620167, 0.265012145, -0.399069, -0.199755281, 0.425340712,
      0.506383598, 0.278146982, -0.164534017, 0.585431278, 0.274939567,
    ],
    [
      1, 0.783359, 0.29237169, 0.548513889, 0.744233251, 0.396695077,
      -0.37177819, 0.27776888, -0.270878762, 0.178947315, 0.486552179,
      -0.274677575, -0.376076847, -0.192331314, -0.177090511, -0.667840481,
    ],
    [
      1, 0.839794934, 0.139173105, -0.524762154, -0.763301969, 0.202436671,
      -0.470946282, -0.126496479, -0.372287244, 0.0802477598, -0.237539962,
      -0.464462668, -0.202020496, 0.290228486, -0.115855977, 0.763506413,
    ],
    [
      1, 0.905849099, -0.35836795, 0.225853547, 0.354358941, -0.562270939,
      -0.307358623, -0.140189886, -0.666452229, -0.478044897, -0.283960253,
      -0.198512182, 0.422491103, -0.0494946465, 0.534051597, -0.430433542,
    ],
    [
      1, 0.970295727, 0, 0.241921902, 0.406574309, 0, -0.5, 0, -0.764655054,
      -0.587507546, 0, -0.594182372, -0, -0.148146302, -0, -0.528994203,
    ],
  ];
  let widthCoefficients = [
    [1.00323582, 1.00215614, 0.999152243, 0.990038335],
    [1.15834534, 1.0939821, 0.926474035, 0.45869],
    [1.34301114, 1.15742362, 0.717799246, 0],
    [1.50422573, 1.17846501, 0.460174114, 0],
    [1.67696583, 1.147506, 0.0619832352, 0],
    [1.78483737, 1.07335603, 0, 0],
    [1.91430533, 0.967857182, 0, 0],
    [2.01644754, 0.869606793, 0, 0],
    [2.12441039, 0.745115161, 0, 0],
    [2.19836354, 0.641445279, 0, 0],
    [2.26663089, 0.523825884, 0, 0],
    [2.30789185, 0.435342163, 0, 0],
    [2.34218574, 0.343246311, 0, 0],
    [2.36116815, 0.278698117, 0, 0],
    [2.37592244, 0.215048239, 0, 0],
    [2.38366747, 0.172251031, 0, 0],
    [2.38945961, 0.131298795, 0, 0],
    [2.39241052, 0.104376309, 0, 0],
    [2.39457059, 0.0790250674, 0, 0],
    [2.39565301, 0.062558271, 0, 0],
    [2.39643598, 0.0471857451, 0, 0],
    [2.3968246, 0.0372655727, 0, 0],
    [2.39710379, 0.0280483589, 0, 0],
    [2.39724183, 0.0221218374, 0, 0],
    [2.39734054, 0.0166298822, 0, 0],
    [2.39738917, 0.0131058795, 0, 0],
    [2.39742374, 0.00984522793, 0, 0],
    [2.39744091, 0.00775544578, 0, 0],
    [2.39745307, 0.00582352886, 0, 0],
    [2.39745903, 0.00458619371, 0, 0],
    [2.39746332, 0.00344291423, 0, 0],
    [2.39746547, 0.00271097128, 0, 0],
  ];

  let context;
  let encoder;
  let bufferSource;

  beforeEach(function() {
    // Create nodes.
    expect(ambisonicOrder ==
      ResonanceAudio.Encoder.validateAmbisonicOrder(ambisonicOrder));
    context =
      new OfflineAudioContext(numberOfChannels, 1, sampleRate);
    encoder = new ResonanceAudio.Encoder(context, {
      ambisonicOrder: ambisonicOrder,
    });
    bufferSource = context.createBufferSource();
    bufferSource.buffer = context.createBuffer(1, 1, sampleRate);
    bufferSource.buffer.getChannelData(0)[0] = 1;

    // Connect audio graph.
    bufferSource.connect(encoder.input);
    encoder.output.connect(context.destination);
    bufferSource.start();
  });

  it('Ensure module produces output.', function(done) {
    context.startRendering().then(function(renderedBuffer) {
      let outputPower = 0;
      for (let i = 0; i < renderedBuffer.numberOfChannels; i++) {
        let buffer = renderedBuffer.getChannelData(i);
        for (let j = 0; j < buffer.length; j++) {
          outputPower += buffer[j] * buffer[j];
        }
      }
      expect(outputPower).to.be.above(0);
      done();
    });
  });

  for (let index = 0; index < numAngles; index++) {
    it('#setDirection: Verify direction [' + index + '].',
      function(done) {
        encoder.setDirection(angles[index][0], angles[index][1]);
        expectedValues = angleCoefficients[index];
        context.startRendering().then(function(renderedBuffer) {
          let error = 0;
          for (let i = 0; i < renderedBuffer.numberOfChannels; i++) {
            let buffer = renderedBuffer.getChannelData(i);
            for (let j = 0; j < buffer.length; j++) {
              error =
                Math.max(error, Math.abs(buffer[j] - expectedValues[i]));
            }
          }
          expect(error).to.be.below(threshold);
          done();
        });
      }
    );
  }

  for (let index = 0; index < numWidths; index++) {
    it('#setSourceWidth: Verify width [' + index + '].',
      function(done) {
        encoder.setDirection(angles[index][0], angles[index][1]);
        encoder.setSourceWidth(widths[index]);
        expectedValues = [];
        for (let i = 0; i < angleCoefficients[index].length; i++) {
          let n = Math.floor(Math.sqrt(i));
          expectedValues[i] =
            angleCoefficients[index][i] * widthCoefficients[index][n];
        }
        context.startRendering().then(function(renderedBuffer) {
          let error = 0;
          for (let i = 0; i < renderedBuffer.numberOfChannels; i++) {
            let buffer = renderedBuffer.getChannelData(i);
            for (let j = 0; j < buffer.length; j++) {
              error =
                Math.max(error, Math.abs(buffer[j] - expectedValues[i]));
            }
          }
          expect(error).to.be.below(threshold);
          done();
        });
      }
    );
  }
});
